"""Draws a sequence of random patterns to practice.

Supports drawing from the pool, recent patterns, the weakest patterns, tags,
and constructs Claymotion patterns.

All input forms are case insensitive.

"""

import random
import time
import string
import os
import sys
import csv
from operator import itemgetter
from spoldzielnia import konfigurator, czytacz

juggle_question = "start"

# sets options with spoldzielnia.py module. 'opcje' is a tuple with options returned by the module.
opcje = konfigurator("shuffle")
trick_pause = opcje[0]
trick_count = opcje[1]
weak_grade = opcje[2]
recent_count = opcje[3]
del opcje

# defines lists with spoldzielnia.py module. 'listy' is a tuple with lists returned by the module.
listy = czytacz()
trick_list = listy[0]
grades_string_list = listy[1]
tag_string_list = listy[2]
del listy

default_tricks = trick_count

os.system(['clear','cls'][os.name == 'nt'])

def general_list():
    """Makes a general trick list.

    This function creates a list from all pattern in the database.
    This function is pretty dumb, but I wrote it to preserve
    consistency of how pattern_list is created in this program.
    """

    pattern_list = trick_list
    extra_msg = " out of all"
    return pattern_list, extra_msg


def tag_selecta():
    """Makes a trick list based on a tag.

    This function creates a list from tagged patterns ignoring priority.
    To create a list of unique tags, the function concatenates string lists
    into one string, breaks the string into list of all tags, then converts
    list-set-list (converting to set removes duplicates, yielding a list of
    unique tags. Finally, the function draws tricks and displays them.
    """

    # Creates the list of unique tags.
    all_tags_string = ""
    for zlicz in range(0, len(trick_list)):
        all_tags_string = all_tags_string + " " + tag_string_list[zlicz].lower()
    unique_tags_list = list(set(all_tags_string.split()))

    # Prints sorted list of tags and prompts for a tag.
    os.system(['clear','cls'][os.name == 'nt'])
    print ""
    print " Available tags:  " + ', '.join(sorted(unique_tags_list))
    print ""
    which_tag = raw_input("Type in a tag ('x' to exit): ").lower()
    print ""
    while which_tag not in unique_tags_list:
        if which_tag == "x":
            os.system(['clear','cls'][os.name == 'nt'])
            break
        else:
            pass
        which_tag = raw_input("    * Hmm... There's no such tag. Try again: ").lower()

    if which_tag != "x":
        # Composes a list of tricks which have the input tag.
        for zlicz in range(0, len(trick_list)):
            if which_tag in tag_string_list[zlicz]:
                pattern_list.append(trick_list[zlicz])
            else:
                pass
        extra_msg = " tagged '" + which_tag + "'"
    else:
        extra_msg = "manual interruption"
    return pattern_list, extra_msg

def srednia_ocena():
    """Calculates average grades and draws out of the weakest patterns.

       This function is needed for the weakest pattern selection.
    """
    
    avg_grades_list = []
    grades_ints_list = []

    # converts lists; required for further computation
    for zlicz in range(0, len(trick_list)):
        grades_aux_ints = [float(y) for y in list(grades_string_list[zlicz])]
        grades_ints_list.append(grades_aux_ints)

    for zlicz in range(0, len(trick_list)):
        # in case of dividing by 0...
        try:
            avg_grade = round(sum(grades_ints_list[zlicz]) / len(grades_ints_list[zlicz]), 2)
        except ZeroDivisionError:
            avg_grade = 0
        
        if avg_grade <= weak_grade:
           pattern_list.append(trick_list[zlicz])
        else:
           pass
    
    extra_msg = " with average grade lower than " + str(weak_grade)
    return pattern_list, extra_msg

def recent_patterns():
    """ Makes a list of the recent pattern based on the option 'recent_count'.
    """
    
    trick_list.reverse()
    pattern_list = trick_list[:recent_count]
    
    extra_msg = " out of " + str(recent_count) + " the most recent patterns"
    return pattern_list, extra_msg
    
def claymotion():
    """ Builds a claymotion pattern from the provided components.
    """
    
    input_tuple = konfigurator("claymotion")   
    clay_string = input_tuple[0]
    clay_count = input_tuple[1]
    clay_components = clay_string.split(',')
    pattern_list = []
    global clay_count

    for zlicz in range(0, clay_count):
        ile_wybrac = random.randint(1, len(clay_components))
        wybrane = random.sample(clay_components, ile_wybrac)
        clay_trick = " Base"
        for zlicz in range(0, ile_wybrac):
            clay_trick = clay_trick + " + " + wybrane[zlicz].strip()

        pattern_list.append(clay_trick) 
    
    # extra_msg controls the behaviour outside the function.
    extra_msg = "claymotion"
    return pattern_list, extra_msg
    
while juggle_question in ["start", "a", "c", "w", "r", "t", "m"]:
    # pattern_list is here to be purged after every round
    pattern_list = []
    # Prompts for another round (with input validator).
    print ""
    print " Which patterns do you want to juggle?  (" + str(trick_count) + " patterns in a round)"
    print ""
    print " [a] Choose from all patterns             [m] Create a Claymotion pattern"
    print " [t] Choose from tags                     [c] Change the number of patterns"
    print " [w] Choose from the weakest patterns"
    print " [r] Choose from recent patterns          [x] Quit"
    juggle_question = raw_input("? ").lower()
    while juggle_question not in ["a", "t", "c", "w", "r", "m", "x"]:
        juggle_question = raw_input("    * Oops! This is not a valid keystroke. Let's try again... ").lower()

    if juggle_question == "a":
        output_tuple = general_list()
    elif juggle_question == "t":
        output_tuple = tag_selecta()
    elif juggle_question == "w":
        output_tuple = srednia_ocena()
    elif juggle_question == "r":
        output_tuple = recent_patterns()
    elif juggle_question == "m":
        output_tuple = claymotion()
    else:
        if juggle_question == "c":
            print ""
            trick_string = raw_input("  * How many patterns in a round? ")
            while trick_string.isdigit() == False or trick_string == "0":
                trick_string = raw_input("    * Nice try, but try again: ")
            trick_count = int(trick_string)
            output_tuple = ["dummy", "dummy"]
        else:
            break
        os.system(['clear','cls'][os.name == 'nt'])
    
    pattern_list = output_tuple[0]
    extra_msg = output_tuple[1]


    if extra_msg != "manual interruption" and extra_msg != "claymotion" and juggle_question != "c":

        # If len(pattern_list) < trick_count, script crashes in drawing. This fixes it.
        if len(pattern_list) < trick_count:
            trick_count = len(pattern_list)
        else:
            pass
        
        os.system(['clear','cls'][os.name == 'nt'])
        print ""
        print " " + str(trick_count) + " patterns" + extra_msg
        print " ++++++++++++++++++++++"
        rand_id_list = random.sample(range(0, len(pattern_list)), trick_count)
        for zlicz in range(0, trick_count):
            current_id = int(rand_id_list[zlicz])
            print ""
            print string.rjust(str(zlicz + 1), 4) + string.ljust("/", 1) + string.ljust(str(trick_count), 3) + string.ljust(pattern_list[current_id], 25)
            time.sleep(trick_pause)
    elif extra_msg == "claymotion":
        os.system(['clear','cls'][os.name == 'nt'])
        print ""
        print " " + str(clay_count) + " Claymotion patterns"
        print " +++++++++++++++++++++"
        for zlicz in range(0, clay_count):
            print ""
            print string.rjust(str(zlicz + 1), 4) + string.ljust("/", 1) + string.ljust(str(clay_count), 3) + string.ljust(pattern_list[zlicz], 70)
            time.sleep(trick_pause)
    else:
        pass
